package com.thinkgem.jeesite.modules.data.rep.web;

import com.thinkgem.jeesite.common.utils.Encodes;
import com.thinkgem.jeesite.modules.data.rep.entity.TfEcReportConfig;
import com.thinkgem.jeesite.modules.data.rep.entity.TfEcReportConfigOut;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletResponse;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 针对没有实体对象，用map存储数据的形式 进行excel导出
 */
public class ExportReportExcel {
    private static Logger log = LoggerFactory.getLogger(ExportReportExcel.class);

    public static ExecutorService executorService = Executors.newFixedThreadPool(10);

    /**
     * 工作薄对象
     */
    private SXSSFWorkbook wb;

    /**
     * 工作表对象
     */
    private Sheet sheet;

    /**
     * 样式列表
     */
    private Map<String, CellStyle> styles;

    /**
     * 当前行号
     */
    private int rownum;

    /**
     * 当前明细页行号
     */
    private int detrownum;

    /**
     * 报表配置
     */
    private TfEcReportConfig report;

    /**
     * 构造函数
     *
     * @param ，传“空值”，表示无标题
     */
    public ExportReportExcel(TfEcReportConfig report) {
        this.report = report;
        initialize(report.getReportName(), report.getReportConfigOuts());
    }



    /**
     * 初始化函数
     *
     * @param title 表格标题，传“空值”，表示无标题
     */
    private void initialize(String title, List<TfEcReportConfigOut> configOuts) {
        this.wb = new SXSSFWorkbook(500);
        this.sheet = wb.createSheet(title);
        this.styles = createStyles(wb);
        // Create title
        int size = 0,maxHeadRow=0,maxHeadCol=0;
        for (TfEcReportConfigOut out:configOuts) {
            if(TfEcReportConfigOut.SPAN_TYPE_DEF.equals(out.getSpanType())) {
                size++;
            } else if(TfEcReportConfigOut.SPAN_TYPE_ROW.equals(out.getSpanType())) {
                size++;
                int rowVal = Integer.parseInt(out.getSpanValue());
                if(maxHeadRow < rowVal){
                    maxHeadRow = rowVal;
                }
            }else if(TfEcReportConfigOut.SPAN_TYPE_COL.equals(out.getSpanType())) {

            }
        }
        if (StringUtils.isNotBlank(title)) {
            Row titleRow = sheet.createRow(rownum++);
            titleRow.setHeightInPoints(30);
            Cell titleCell = titleRow.createCell(0);
            titleCell.setCellStyle(styles.get("title"));
            titleCell.setCellValue(title);
            sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(),
                    titleRow.getRowNum(), titleRow.getRowNum(),size- 1));
        }

        // Create header
        if (configOuts == null) {
            throw new RuntimeException("headerList not null!");
        }
        Row headerRow = sheet.createRow(rownum++);
        headerRow.setHeightInPoints(16);
        TfEcReportConfigOut reportConfigOut = null;
        int cellNum = 0; //列数目
        int colIndex = 0; //列移动标记
        int rowIndex = 0; //行移动标记

        try {
            for (int i = 0; i < configOuts.size(); i++) {
                reportConfigOut = configOuts.get(i);
                String spanType = reportConfigOut.getSpanType();

                if (TfEcReportConfigOut.SPAN_TYPE_COL.equals(spanType)) {
                    int start = cellNum;
                    cellNum = cellNum + Integer.parseInt(reportConfigOut.getSpanValue()) - 1;
                    sheet.addMergedRegion(new CellRangeAddress(rowIndex, rowIndex, start, cellNum++));
                    Cell cell = headerRow.createCell(start);
                    cell.setCellStyle(styles.get("header"));
                    cell.setCellValue(reportConfigOut.getItemName());
                } else if (TfEcReportConfigOut.SPAN_TYPE_ROW.equals(spanType)) {
                    int start = rowIndex = rownum - 1;
                    int end = start + Integer.parseInt(reportConfigOut.getSpanValue()) - 1;
                    sheet.addMergedRegion(new CellRangeAddress(start, end, cellNum, cellNum));
                    Cell cell = headerRow.createCell(cellNum++);
                    cell.setCellStyle(styles.get("header"));
                    cell.setCellValue(reportConfigOut.getItemName());
                    if (Integer.parseInt(reportConfigOut.getSpanValue()) == maxHeadRow) {
                        colIndex++;
                    }
                } else if (TfEcReportConfigOut.SPAN_TYPE_DEF.equals(spanType)) {
                    Cell cell = headerRow.createCell(cellNum++);
                    cell.setCellStyle(styles.get("header"));
                    cell.setCellValue(reportConfigOut.getItemName());
                }
                if (cellNum == size&& i != configOuts.size()-1) {
                    cellNum = colIndex;//从头开始
                    headerRow = sheet.createRow(rownum++);
                    rowIndex++;
                }
            }
        }catch(Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 创建表格样式
     *
     * @param wb 工作薄对象
     * @return 样式列表
     */
    private Map<String, CellStyle> createStyles(Workbook wb) {
        Map<String, CellStyle> styles = new HashMap<String, CellStyle>();

        CellStyle style = wb.createCellStyle();
        style.setAlignment(CellStyle.ALIGN_CENTER);
        style.setVerticalAlignment(CellStyle.VERTICAL_CENTER);
        Font titleFont = wb.createFont();
        titleFont.setFontName("Arial");
        titleFont.setFontHeightInPoints((short) 16);
        titleFont.setBoldweight(Font.BOLDWEIGHT_BOLD);
        style.setBorderBottom(HSSFCellStyle.BORDER_THIN); //下边框
        style.setBorderLeft(HSSFCellStyle.BORDER_THIN);//左边框
        style.setBorderTop(HSSFCellStyle.BORDER_THIN);//上边框
        style.setBorderRight(HSSFCellStyle.BORDER_THIN);//右边框
        style.setFont(titleFont);
        styles.put("title", style);

        style = wb.createCellStyle();
        style.setVerticalAlignment(CellStyle.VERTICAL_CENTER);
        style.setBorderRight(CellStyle.BORDER_THIN);
        style.setRightBorderColor(IndexedColors.BLACK.getIndex());
        style.setBorderLeft(CellStyle.BORDER_THIN);
        style.setLeftBorderColor(IndexedColors.BLACK.getIndex());
        style.setBorderTop(CellStyle.BORDER_THIN);
        style.setTopBorderColor(IndexedColors.BLACK.getIndex());
        style.setBorderBottom(CellStyle.BORDER_THIN);
        style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
        Font dataFont = wb.createFont();
        dataFont.setFontName("Arial");
        dataFont.setFontHeightInPoints((short) 10);
        style.setFont(dataFont);
        styles.put("data", style);

        style = wb.createCellStyle();
        style.cloneStyleFrom(styles.get("data"));
        style.setAlignment(CellStyle.ALIGN_LEFT);
        styles.put("data1", style);

        style = wb.createCellStyle();
        style.cloneStyleFrom(styles.get("data"));
        style.setAlignment(CellStyle.ALIGN_LEFT);
        style.setDataFormat(wb.createDataFormat().getFormat("yyyy-MM-dd"));
        styles.put("date1", style);

        style = wb.createCellStyle();
        style.cloneStyleFrom(styles.get("data"));
        style.setAlignment(CellStyle.ALIGN_CENTER);
        styles.put("data2", style);

        style = wb.createCellStyle();
        style.cloneStyleFrom(styles.get("data"));
        style.setAlignment(CellStyle.ALIGN_CENTER);
        style.setDataFormat(wb.createDataFormat().getFormat("yyyy-MM-dd"));
        styles.put("date2", style);

        style = wb.createCellStyle();
        style.cloneStyleFrom(styles.get("data"));
        style.setAlignment(CellStyle.ALIGN_RIGHT);
        styles.put("data3", style);

        style = wb.createCellStyle();
        style.cloneStyleFrom(styles.get("data"));
        style.setAlignment(CellStyle.ALIGN_RIGHT);
        style.setDataFormat(wb.createDataFormat().getFormat("yyyy-MM-dd"));
        styles.put("date3", style);

        style = wb.createCellStyle();
        style.cloneStyleFrom(styles.get("data"));
        //style.setWrapText(true);
        style.setAlignment(CellStyle.ALIGN_CENTER);
        style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex());
        style.setFillPattern(CellStyle.SOLID_FOREGROUND);
        Font headerFont = wb.createFont();
        headerFont.setFontName("Arial");
        headerFont.setFontHeightInPoints((short) 10);
        headerFont.setBoldweight(Font.BOLDWEIGHT_BOLD);
        headerFont.setColor(IndexedColors.WHITE.getIndex());
        style.setFont(headerFont);
        styles.put("header", style);

        return styles;
    }

    /**
     * 添加一行
     *
     * @return 行对象
     */
    public Row addRow() {
        return sheet.createRow(rownum++);
    }


    /**
     * 添加一行
     *
     * @return 行对象
     */
    public Row addDetRow(Sheet sheet) {
        return sheet.createRow(detrownum++);
    }


    /**
     * 添加一个单元格
     *
     * @param row    添加的行
     * @param column 添加列号
     * @param val    添加值
     * @return 单元格对象
     */
    public Cell addCell(Row row, int column, Object val) {
        return this.addCell(row, column, val, 0);
    }

    /**
     * 添加一个单元格
     *
     * @param row    添加的行
     * @param column 添加列号
     * @param val    添加值
     * @param align  对齐方式（1：靠左；2：居中；3：靠右）
     * @return 单元格对象
     */
    public Cell addCell(Row row, int column, Object val, int align) {
        Cell cell = row.createCell(column);
        CellStyle style = styles.get("data" + (align >= 1 && align <= 3 ? align : ""));
        boolean isDate = false;
//            if (val == null){ 
//                cell.setCellValue("");
//            }else{
//                cell.setCellValue(val.toString());
//            }
        try {
            if (val == null) {
                cell.setCellValue("");
            } else if (val instanceof String) {
                cell.setCellValue((String) val);
                //解决中文自适应问题
                int width = cell.getStringCellValue().getBytes().length * 256;
                sheet.setColumnWidth(column, width < 3000 ? 3000 : width);
            } else if (val instanceof Integer) {
                cell.setCellValue((double) ((Integer) val).intValue());
            } else if (val instanceof Long) {
                cell.setCellValue((double) ((Long) val).longValue());
            } else if (val instanceof Double) {
                cell.setCellValue(((Double) val).doubleValue());
            } else if (val instanceof Float ||val instanceof BigDecimal) {
                cell.setCellValue((double) ((Float) val).floatValue());
            } else if (val instanceof Date) {
                SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd");
                String sDate = s.format((Date) val);
                cell.setCellValue(sDate);
                //cell.setCellValue((Date) val);
                //isDate = true;
            } else {
                cell.setCellValue((String) Class.forName(this.getClass().getName().replaceAll(this.getClass().getSimpleName(), "fieldtype." + val.getClass().getSimpleName() + "Type")).getMethod("setValue", new Class[]{Object.class}).invoke((Object) null, new Object[]{val}));
            }
            /*if(isDate) {
                //style = styles.get("date" + (align >= 1 && align <= 3 ? align : ""));
            }*/
        } catch (Exception var9) {
            log.info("excel导入失败：" + var9.toString());
            cell.setCellValue(val.toString());
        }

        cell.setCellStyle(style);
        //sheet.autoSizeColumn(column, true);

        return cell;
    }

    /**
     * 添加数据
     */
    public ExportReportExcel setDataList(List<Map<String, Object>> list) {
        for (Map<String, Object> map : list) {
            int colunm = 0;
            Row row = this.addRow();
            for (TfEcReportConfigOut configOut : report.getReportConfigOuts()) {
                if(!configOut.getSpanType().equals(TfEcReportConfigOut.SPAN_TYPE_COL))
                    this.addCell(row, colunm++, map.get(configOut.getItemCode()), 0);
            }
        }
        return this;
    }


    /**
     * 输出数据流
     */
    public ExportReportExcel write(OutputStream os) throws IOException {
        wb.write(os);
        return this;
    }

    /**
     * 输出到客户端
     */
    public ExportReportExcel write(HttpServletResponse response, String fileName) throws IOException {
        response.reset();
        response.setContentType("application/octet-stream; charset=utf-8");
        response.setHeader("Content-Disposition", "attachment; filename=" + Encodes.urlEncode(fileName));
        write(response.getOutputStream());
        return this;
    }

    /**
     * 输出到文件
     */
    public ExportReportExcel writeFile(String name) throws FileNotFoundException, IOException {
        FileOutputStream os = new FileOutputStream(name);
        this.write(os);
        return this;
    }

    /**
     * 清理临时文件
     */
    public ExportReportExcel dispose() {
        wb.dispose();
        return this;
    }
}
